#region Using directives

using System;
using System.Collections;
using FighterChessEngine.Enum;
using FighterChessEngine.Event;
using FighterChessEngine.FC_Board;

#endregion

namespace FighterChessEngine.FC_Fighter
{
    /// <summary>
    /// Summary description for Fighter.
    /// </summary>
    public class Fighter
    {   
        #region Atributes
        protected string name;
        protected string symbol;
        protected FighterType type;
        protected Owner owner;
        protected Square initPos; // SquareType is DontCare
        protected Square currentPos; // SquareType is DontCare
        protected ArrayList arrNextPos; 
        protected bool died;
        protected int fullHp;
        protected int hp;
        protected int level;
        protected Facing facing;
        protected Stance stance;
        #endregion

        #region Properties
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
        public string Symbol
        {
            get { return symbol; }
            set { symbol = value; }
        }
        public FighterType Type
        {
            get { return type; }
            set { type = value; }
        }
        public Owner Owner
        {
            get { return owner; }
            set 
            {
                owner = value; 

                if (owner == Owner.White) // face right
                {
                    facing = Facing.Right;
                }
                else if (owner == Owner.Black) // face left
                {
                    facing = Facing.Left;
                }
            }
        }
        public bool Died
        {
            get { return died; }
            set { died = value; }
        }
        public Square InitPos
        {
            get { return initPos; }
            set { initPos = value; }
        }
        public Square CurrentPos
        {
            get { return currentPos; }
            set { currentPos = value; }
        }
        public ArrayList NextPositions
        {
            get { return arrNextPos; }
            set { arrNextPos = value; }
        }
        public int HP
        {
            get { return hp; }
            set { hp = value; }
        }
        public int Level
        {
            get { return level; }
            set { level = value; }
        }
        public Stance Stance
        {
            get { return stance; }
            set { stance = value; }
        }
        public Facing Facing
        {
            get { return facing; }
            set { facing = value; }
        }

        public string Informations
        {
            get
            {
                string info = "";
                info += owner == Owner.White ? "W" : "B";
                info += name;
                info += " Lvl:" + level.ToString();
                info += " HP:" + hp.ToString();

                return info;
            }
        }
        #endregion

        #region Methods
        public Fighter()
        {
            name = "fighter";
            symbol = "F";
            type = FighterType.Fighter;
            owner = Owner.None;
            initPos = null;
            currentPos = null;
            arrNextPos = new ArrayList();
            died = false;
            fullHp = 100;
            hp = fullHp;
            level = 0;
            facing = Facing.None;
            stance = Stance.Sit;
        }

        public Fighter(Square pos) : this()
        {
            this.initPos = new Square(pos.Row, pos.Col);
            this.currentPos = new Square(pos.Row, pos.Col);
        }

        public Fighter(Owner owner, Square pos)
            : this(pos)
        {
            this.Owner = owner;
        }

        public Fighter(string strFighter) : this()
        {
            // strFighter : Symbol,Owner,Lvl,HP,Facing,Row,Col
            // ex: KI,1,10,90,1,4,1
            
            char[] sep = {','};
            string[] arrInfos = strFighter.Split(sep);
            owner = (Owner)int.Parse(arrInfos[1]);
            level = int.Parse(arrInfos[2]);
            hp = int.Parse(arrInfos[3]);
            facing = (Facing) int.Parse(arrInfos[4]);
            this.currentPos = new Square(int.Parse(arrInfos[5]), int.Parse(arrInfos[6]), SquareType.DontCare);
        }

        public string ToSaveString()
        {
            string str = "";
            str += this.symbol + ",";
            int iOwner = (int)this.owner;
            str += iOwner.ToString() + ",";
            str += this.level.ToString() + ",";
            str += this.hp.ToString() + ",";
            int iFacing = (int)this.facing;
            str += iFacing.ToString() + ",";
            str += this.currentPos.Row.ToString() + ",";
            str += this.currentPos.Col.ToString();

            return str;
        }

        public void StandUp()
        {
            this.Stance = Stance.Stand;
            ActionStandUp(this);
        }

        public void SitDown()
        {   
            this.Stance = Stance.Sit;
            ActionSitDown(this);
        }

        public void Select()
        {
            //StandUp();
            this.Stance = Stance.Stand;
            ActionClick(this);
        }

        public bool CanMoveTo(int row, int col)
        {
            // can't move when sitting
            if (stance == Stance.Sit)
                return false;

            Square dest = new Square(row, col);
            foreach (Square square in arrNextPos)
            {
                if (square.Equals(dest))
                    return true;
            }

            return false;
        }
        
        public bool MoveTo(int row, int col) 
        {
            /*if (!CanMoveTo(row, col))
                return false;*/

            // if move to right -> facing right 
            // else facing left
            if (col > currentPos.Col)
                facing = Facing.Right;
            else if (col < currentPos.Col) 
                facing = Facing.Left;

            Move move = new Move(currentPos.Row, currentPos.Col, row, col);
            currentPos.Row = row;
            currentPos.Col = col;
            ActionMove(this, new EventMoveArgs(move));
            return true;
        }

        public void RestoreHP()
        {
            hp = fullHp;
            ActionRestoreHP(this);
        }

        public void LevelUp(int increment)
        {
            if (level == 99) // lvl max already;
                return;

            level += increment;
            if (level > 99) // lvl max = 99
                level = 99;

            ActionLevelUp(this, increment);
        }

        public void KilledBy(Fighter killer)
        {
            died = true;
            ActionDie(this, killer);
        }

        // return :- 1 if win, 0 if both died
        public int Fight(Fighter enemy) 
        {
            //this.stance = Stance.Fight;
            //enemy.stance = Stance.Fight;

            if (this.level <= enemy.Level && this.hp <= enemy.HP)
            {
                ActionFight(this, enemy);
                enemy.KilledBy(this);
                this.KilledBy(null);
                return 0;
            }

            if (this.level == enemy.Level)
            {
                this.hp -= Math.Max(this.hp * 50 / 100, 25);
                this.level += 1;
                enemy.KilledBy(this);
            }
            else if (this.level > enemy.Level)
            {
                this.hp -= Math.Max(this.hp * 20 / 100, 10);
                this.level += 1;
                enemy.KilledBy(this);
            }
            else if (this.level < enemy.Level)
            {
                this.hp -= Math.Max(this.hp * 70 / 100, 35);
                this.level += enemy.Level - this.level + 1;
                enemy.KilledBy(this);
            }

            if (this.hp <= 0) // die 'cause run out of HP
            {
                this.KilledBy(null);
                return 0;
            }

            
            ActionFight(this, enemy);
            return 1;
        }

        public virtual void UpdateNextPositions(Fighter[,] fighters) 
        {
            arrNextPos.Clear();
        }

        #endregion

        #region Event
        public delegate void EventMoveHandler(Fighter fighter, EventMoveArgs e);
        public event EventMoveHandler ActionMove;
        public delegate void EventSitDownHandler(Fighter fighter);
        public event EventSitDownHandler ActionSitDown;
        public delegate void EventStandUpHandler(Fighter fighter);
        public event EventStandUpHandler ActionStandUp;
        public delegate void EventHpRestoreHandler(Fighter fighter);
        public event EventHpRestoreHandler ActionRestoreHP;
        public delegate void EventLevelUpHandler(Fighter fighter, int increment);
        public event EventLevelUpHandler ActionLevelUp;
        public delegate void EventClickHandler(Fighter fighter);
        public event EventClickHandler ActionClick;
        public delegate void EventDieHandler(Fighter victim, Fighter killer);
        public event EventDieHandler ActionDie;
        public delegate void EventFightHandler(Fighter attacker, Fighter defender);
        public event EventFightHandler ActionFight;
        #endregion

        #region Support Funcs
        // return:
        // 2: enemy
        // 1: ally
        // 0: empty
        // -1: error
        protected int CheckSquare(Fighter[,] fighters, int row, int col)
        {
            try
            {
                if (fighters[row, col] == null)
                    return 0; // empty square
            }
            catch (Exception ex)
            {
                return -1; // out of bound
            }


            if (fighters[row, col].Owner == this.owner)
                return 1; // ally
            else
                return 2; // enemy

        }

        protected bool AddStopPosition(Fighter[,] fighters, int row, int col)
        {
            /*if (fighters[row, col] != null)
                if (fighters[row, col].Owner == this.owner) // ally
                {
                    return true;
                }
                else // enemy
                {
                    arrNextPos.Add(new Square(row, col));
                    return true;
                }*/
            int checkResult = CheckSquare(fighters, row, col);
            if (checkResult == 1) // ally
            {
                return true;
            }
            else if (checkResult == 2) // enemy
            {
                arrNextPos.Add(new Square(row, col));
                return true;
            }

            return false;
        }
        #endregion
    }
}
